
#define DIRECTINPUT_VERSION 0x0800

#include "cegfx/cemouse.h"
#define MAX_BUTTON 3


static DIOBJECTDATAFORMAT diodf_m[] = {
	{ &GUID_XAxis, FIELD_OFFSET(ceMouse::MouseData, xaxis),			 DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
	{ &GUID_YAxis, FIELD_OFFSET(ceMouse::MouseData, yaxis),			 DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
	{ 0,           FIELD_OFFSET(ceMouse::MouseData, buttons[0]), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
	{ 0,					 FIELD_OFFSET(ceMouse::MouseData, buttons[1]), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
	{ 0,					 FIELD_OFFSET(ceMouse::MouseData, buttons[2]), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
};

static DIDATAFORMAT didf_m = {
	sizeof (DIDATAFORMAT),
	sizeof (DIOBJECTDATAFORMAT),
	DIDF_RELAXIS,
	sizeof (ceMouse::MouseData),
	sizeof (diodf_m) / sizeof (DIOBJECTDATAFORMAT),
	diodf_m
};




ceMouse::ceMouse ()
	: mouseDevice (0)
	, idx0(0)
	, idx1(1)
{
}


ceMouse::~ceMouse ()
{
	if (mouseDevice)
	{
		mouseDevice->Release ();
	}
}

IQF_IMPLEMENTATION_BEGIN(ceMouse);
IQF_IMPLEMENTATION_END();

bool ceMouse::Initialize (LPDIRECTINPUT8 input, HWND hWnd)
{
	if (!input) return false;
	
	if (FAILED(input->CreateDevice (GUID_SysMouse, (LPDIRECTINPUTDEVICE8*)&mouseDevice, 0))) return false;
	if (!mouseDevice)
	{
		return false;
	}
	mouseDevice->AddRef ();
	if (FAILED(mouseDevice->SetDataFormat (&didf_m))) return false;

	mouseDevice->SetCooperativeLevel (hWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
	return true;
}

bool ceMouse::UpdateState ()
{
	static LONG originX;
	static LONG originY;
	static bool init = false;


	HRESULT hr = mouseDevice->Poll ();
	if (FAILED(hr))
	{
		hr = mouseDevice->Acquire ();
		while (hr == DIERR_INPUTLOST)
		{
			hr = mouseDevice->Acquire ();
		}
		if (FAILED(mouseDevice->Poll ())) return false;
	}
	
	// swap the states
	if (idx0)
	{
		idx0 = 0;
		idx1 = 1;
	}
	else
	{
		idx0 = 1;
		idx1 = 0;
	}

	mouseDevice->GetDeviceState (sizeof (MouseData), &mouseData[idx0]);

	if (!init)
	{
		originX = mouseData[idx0].xaxis;
		originY = mouseData[idx0].yaxis;
	}
	mouseData[idx0].xaxis -= originX;
	mouseData[idx1].yaxis -= originY;
	memcpy (&mouseData[idx1], &mouseData[idx0], sizeof (MouseData));

	if (!init)
	{
		memcpy (&mouseData[idx1], &mouseData[idx0], sizeof (MouseData));
		init = true;
	}

	return true;
}


int ceMouse::GetDX () const
{
	return mouseData[idx0].xaxis;
}

int ceMouse::GetDY () const
{
	return mouseData[idx0].yaxis;
}

bool ceMouse::IsButtonDown (int button) const
{
	if (button >= MAX_BUTTON || button < 0)
	{
		return false;
	}
	return mouseData[idx0].buttons[button] != 0;
}

bool ceMouse::IsButtonUp (int button) const
{
	if (button >= MAX_BUTTON || button < 0)
	{
		return false;
	}
	return mouseData[idx0].buttons[button] == 0;
}

bool ceMouse::IsButtonPressed (int button) const
{
	if (button >= MAX_BUTTON || button < 0)
	{
		return false;
	}

	return mouseData[idx0].buttons[button] != 0 && mouseData[idx1].buttons[button] == 0;
}


bool ceMouse::IsButtonReleased (int button) const
{
	if (button >= MAX_BUTTON || button < 0)
	{
		return false;
	}

	return mouseData[idx0].buttons[button] == 0 && mouseData[idx1].buttons[button] != 0;
}

